﻿package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;	
	import flash.events.Event;
	import flash.filters.BlurFilter;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.text.TextField;	

	/*
	 * coded by moka 2009 / 07/ 19 
	 * name : moka's follower
	 */
	
	public class Main extends Sprite 
	{		
		private var bg:Bitmap;
		private var bmpBuffer:BitmapData;
		private var fa:Array;
		private var fnum:uint;
		
		public function Main():void 
		{			
			stage.scaleMode = "noScale";
			bg = addChild(new Bitmap(new BitmapData(640, 480, false, 0))) as Bitmap;
			
			// create 50 followers
			fnum = 50;
			fa = new Array();			
			for (var i:uint = 0; i < fnum;i++){
				fa.push(new Follower( 640 * Math.random(), 480 * Math.random(), 5 + Math.random() * 10));
				// apply the image to the follower
				var color:Number = 0xFFFFFF;
				fa[i].graphics.lineStyle(20*Math.random(), color*Math.random());
				fa[i].graphics.beginFill(color);
				fa[i].graphics.drawCircle(0, 0, 1);
				fa[i].graphics.endFill();
			}

			// event registration
			stage.addEventListener(Event.ENTER_FRAME, onProcess);	
			
			// Moka's work 2009
			(addChild(new TextField()) as TextField).htmlText = "<font color='#FFFFFF'>Moka's work 2009</font>";
		}		

		private function onProcess(e:Event):void {	
			bmpBuffer = bg.bitmapData.clone(); // copy the bitmapdata from bg		
			bg.bitmapData.draw(bmpBuffer, new Matrix(), new ColorTransform(0, 0, 0,0.05)); // draw transparent image
			
			for (var i:uint = 0; i < fnum;i++){
				fa[i].follow(mouseX, mouseY); // track the mouse
				bg.bitmapData.draw(fa[i],new Matrix(1,0,0,1,fa[i].x,fa[i].y));// draw follower image			
			}

			bg.bitmapData.applyFilter(bg.bitmapData, bg.bitmapData.rect, new Point(), new BlurFilter(2,2,1));// apply the blurfilter
		}

	}
	
	
}

/*
 * coded by moka 2009 / 07/ 19 
 * name : moka's follower
 */

class Follower extends flash.display.Sprite {
	// essential property (position,vector,speed..etc)
	private var _x:Number;
	private var _y:Number;
	private var _vx:Number;
	private var _vy:Number;
	private var _speed:Number;
	private var _theta:Number;
	private var _k:Number;
	private var _bdW:Number; // stage boundaries
	private var _bdH:Number;
	private var _findRange:Number;
	
	public function Follower( px:Number, py:Number, spd:Number, fr:Number = 200 ,stgW:Number = 640, stgH:Number = 480, angle:Number = 5, k:Number = 0.6) {		
		this._x = _x = px;
		this._y = _y = py;
		_speed = spd;
		_theta = angle;
		_k = k;
		_vx = _speed * _k;
		_vy = _speed * _k;
		_bdW = stgW;
		_bdH = stgH;
		_findRange = fr;
	}
	
	public function follow( mx:Number, my:Number ):void {		
		// find the target between +/- theta
		var rad:Number = _theta / 180 * Math.PI;
		var vx1:Number = _vx * Math.cos(rad) - _vy * Math.sin(rad);
		var vy1:Number = _vx * Math.sin(rad) + _vy * Math.cos(rad);
		var vx2:Number = _vx * Math.cos(rad) + _vy * Math.sin(rad);
		var vy2:Number = -_vx * Math.sin(rad) + _vy * Math.cos(rad);
			
		var px:Number = mx - _x;
		var py:Number = my - _y;
		
		// find the target when the distant between follower and target is lower than the range
		if (Math.sqrt((mx - _x) * (mx - _x) + (my - _y) * (my - _y)) < _findRange)
			// The comparison of length of projection between v1 and v2 on v 
			if ( px * vx1 + py * vy1 >= px * vx2 + py * vy2 ) {
				_vx = vx1;
				_vy = vy1;
			}else {
				_vx = vx2;
				_vy = vy2;
			}
		
		// move the sprite
		_x += _vx;
		_y += _vy;		
		
		// boundary
		if (_x > _bdW+this.width) this.x = _x = -this.width;
		if (_x < -this.width) this.x = _x = _bdW+this.width;
		if (_y > _bdH+this.height) this.y = _y = -this.height;
		if (_y < -this.height) this.y = _y = _bdH+this.height;
		
		// smooth the movement
		this.x += (_x - this.x) / 3;
		this.y += (_y - this.y) / 3;
	}
	
}